#include <vector>
#include <functional>
#include <numeric>
//#include <exception>

/*
void reTitleY(TCanvas *pl, TString ytitle) {
    TH1 *first = (TH1*) pl->GetListOfPrimitives()->At(0);
    TH1 *last = (TH1*) pl->GetListOfPrimitives()->At(pl->GetListOfPrimitives()->GetSize()-1);
    if (first) reTitleTAxis(first->GetYaxis(), ytitle);
    if (last)  reTitleTAxis(last->GetYaxis(), ytitle);
} 
*/


void setRangeY(TCanvas *c, double min=0, double max=1.1) {
    for (size_t i = 0, n = c->GetListOfPrimitives()->GetSize(); i < n; ++i) {
        TObject *o = c->GetListOfPrimitives()->At(i);
        if (o->InheritsFrom("TH1")) ((TH1*) o)->GetYaxis()->SetRangeUser(min,max);
    }
}


void setRangeY( TVirtualPad *c, double min=0, double max=1.1) {
    for (size_t i = 0, n = c->GetListOfPrimitives()->GetSize(); i < n; ++i) {
        TObject *o = c->GetListOfPrimitives()->At(i);
        if (o->InheritsFrom("TH1")) ((TH1*) o)->GetYaxis()->SetRangeUser(min,max);
    }
}

TH1F * TH1Clone(TH1F * h,TString name="tmp", TString title="",double scale=1.0)
{
/*
int  nbins=h->GetNbinsX();
double xmin=h->GetXaxis()->GetXmin();
double xmax=h->GetXaxis()->GetXmax();

TH1F * hist = new TH1F(name.Data(),title.Data(),nbins,xmin,xmax);


for (int i=1; i<=nbins;i++){
hist->SetBinContent(i,h->GetBinContent(i));
hist->SetBinError(i,h->GetBinError(i));
}
hist->SetEntries(h->GetEntries());
*/
TH1F* hist = (TH1F*) h->Clone(name.Data());
hist->SetTitle(title.Data());
//hist->Scale(scale);
//hist->Rebin(rebin);

return hist;
}

TH1 * ChangeBinning(TH1 *h, TString name="tmp",int nbins=50,double xmin=0.0,double xmax=1.0)
{
TString title = h->GetTitle();


TH1F * hist = new TH1F(name.Data(),title.Data(),nbins,xmin,xmax);

for (Int_t i=0;i<100000;i++)hist->Fill(h->GetRandom());

//hist->FillRandom(h,10000);
hist->Scale(h->Integral()/hist->Integral());
hist->Sumw2();


return hist;
}



double CalculBinVal(TH1 * h_old,TH1 * h_new, int bin_new, std::vector<int> * bins_old )
{
double val=0;
double binLowEdge;
double binHiEdge;

for (unsigned int i=0; i<bins_old->size();i++) {
//cout<<"i "<<i<<endl;
//cout<<"bins_old "<<(*bins_old)[i]<<endl;

if ((*bins_old)[i]<0) continue;

binLowEdge=h_old->GetBinLowEdge((*bins_old)[i]);
binHiEdge=binLowEdge+h_old->GetBinWidth((*bins_old)[i]);
double widthBin=h_old->GetBinWidth((*bins_old)[i]);

if (widthBin == 0) continue;


double low_lowDiff=h_new->GetBinLowEdge(bin_new)-binLowEdge;
double low_hiDiff=h_new->GetBinLowEdge(bin_new)-binHiEdge;
double hi_lowDiff=h_new->GetBinLowEdge(bin_new)-binLowEdge + h_new->GetBinWidth(bin_new);
double hi_hiDiff=h_new->GetBinLowEdge(bin_new)-binHiEdge + h_new->GetBinWidth(bin_new);

/*
cout<<"low_lowDiff= "<<low_lowDiff<<endl;
cout<<"low_hiDiff= "<<low_hiDiff<<endl;
cout<<"hi_lowDiff= "<<hi_lowDiff<<endl;
cout<<"hi_hiDiff= "<<hi_hiDiff<<endl;
*/

double ratio=1.0;
if (hi_lowDiff<0e0) break;

if (low_lowDiff<0.0 && hi_hiDiff<0.0 && hi_lowDiff>=0.0) ratio=hi_lowDiff/widthBin;
if (low_lowDiff>=0.0 && hi_hiDiff<=0.0) ratio=h_new->GetBinWidth(bin_new)/widthBin;
if (low_lowDiff>=0.0  && hi_hiDiff>0.0 && low_hiDiff<0.0)  ratio=-low_hiDiff/widthBin;
/*
cout<<"ratio = "<<ratio<<endl;
cout<<"val 1 -->  "<<val<<endl;
cout<<"h_old->GetBinContent(i) "<<h_old->GetBinContent(i)<<endl;
*/
val+=h_old->GetBinContent(i)*ratio;

if (hi_hiDiff>=0e0) (*bins_old)[i]=-1;

}

return val;
}


TH1 * ChangeBinning2(TH1 *h, TString name="tmp",int nbins=50,double xmin=0.0,double xmax=1.0)
{
std::vector<int> * bins_to_proces=new vector<int>() ;

for (int i=1; i<=h->GetNbinsX();i++) bins_to_proces->push_back(i);


TString title = h->GetTitle();
TH1F * hist = new TH1F(name.Data(),title.Data(),nbins,xmin,xmax);


double val;

for (int i=1;  i<=hist->GetNbinsX();i++)
{
///
int bin_old;
double binLowEdge_old;
double binHiEdge_old;
double val_old;

val=CalculBinVal(h,hist,i,bins_to_proces);
hist->SetBinContent(i,val);
}

hist->Sumw2();


return hist;

}

